package com.house.quartz;

import lombok.extern.log4j.Log4j2;
import org.quartz.*;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

@Log4j2
@Component
public class QuartzManager implements ApplicationRunner, DisposableBean {
    private static String DEFAULT_JOB_GROUP_NAME = "JOB_GROUP_NAME";
    private static String DEFAULT_TRIGGER_GROUP_NAME = "TRIGGER_GROUP_NAME";

    @Autowired
    private Scheduler scheduler;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        this.start();
    }

    @Override
    public void destroy() throws Exception {
        this.shutdown();
    }

    /**
     * 启动任务调度器
     */
    public void start() {
        try {
            if (!scheduler.isStarted()) {
                scheduler.start();
                System.out.println("quartz启动成功…");
            }
        } catch (SchedulerException e) {
            log.error(e);
            System.out.println("任务启动失败…");
        }
    }

    /**
     * 关闭任务调度器
     */
    public void shutdown() {
        try {
            if (scheduler.isStarted()) {
                scheduler.shutdown();
                Thread.sleep(1000);
                System.out.println("quartz关闭成功…");
            }
        } catch (Exception e) {
            log.error(e);
            System.out.println("任务关闭失败…");
        }
    }

    /**
     * 添加一个定时任务，使用默认的任务组名，触发器名，触发器组名
     *
     * @param jobName 任务名
     * @param jobCls  任务
     * @param time    时间设置，参考quartz说明文档
     * @throws SchedulerException
     * @throws java.text.ParseException
     */
    public void addJob(String jobName, Class jobCls, String time)
            throws SchedulerException {
        addJob(jobName, jobCls, time, null);
    }

    /**
     * 添加一个定时任务，使用默认的任务组名，触发器名，触发器组名
     *
     * @param jobName 任务名
     * @param jobCls  任务
     * @param time    时间设置，参考quartz说明文档
     * @param data    参数集
     * @throws SchedulerException
     */
    public void addJob(String jobName, Class jobCls, String time, Map<String, Object> data)
            throws SchedulerException {
        //Scheduler scheduler = sf.getScheduler();
        //如果job已经存在，则先移除重新添加
        if (scheduler.checkExists(JobKey.jobKey(jobName, DEFAULT_JOB_GROUP_NAME)))
            removeJob(jobName);
        JobDetail jobDetail = newJob(jobCls).withIdentity(jobName, DEFAULT_JOB_GROUP_NAME).build();//任务名，任务组，任务执行类
        if (data != null && data.size() > 0) {
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                jobDetail.getJobDataMap().put(entry.getKey(), entry.getValue());
            }
        }
        //触发器
        CronTrigger trigger =
                newTrigger().withIdentity(jobName, DEFAULT_TRIGGER_GROUP_NAME).withSchedule(cronSchedule(time)).build();//触发器名,触发器组
        // 调度容器设置JobDetail和Trigger
        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 修改一个任务的触发时间(使用默认的任务组名，触发器名，触发器组名)
     *
     * @param jobName
     * @param time
     * @throws SchedulerException
     */
    public void modifyJobTime(String jobName, String time)
            throws SchedulerException {
        //Scheduler scheduler = sf.getScheduler();
        /*
        CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(TriggerKey.triggerKey(jobName,
        DEFAULT_TRIGGER_GROUP_NAME));
        if(oldTrigger==null)
            return;
        TriggerBuilder triggerBuilder = oldTrigger.getTriggerBuilder();
        //表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(time);
        Trigger newTrigger = triggerBuilder.withSchedule(scheduleBuilder).build();
        scheduler.rescheduleJob(oldTrigger.getKey(), newTrigger);
        */
        if (!checkJobKeyExists(jobName)) return;
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(TriggerKey.triggerKey(jobName,
                DEFAULT_TRIGGER_GROUP_NAME));
        if (trigger == null)
            return;
        String oldTime = trigger.getCronExpression();
        log.info("修改任务：" + jobName + "\n执行时间：" + time);
        if (!oldTime.equalsIgnoreCase(time)) {
            JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(jobName, DEFAULT_JOB_GROUP_NAME));
            Map jobDataMap = jobDetail.getJobDataMap();
            Iterator entries = jobDataMap.entrySet().iterator();
            HashMap<String, Object> data = new HashMap<String, Object>();
            while (entries.hasNext()) {
                Map.Entry entry = (Map.Entry) entries.next();
                data.put(entry.getKey().toString(), entry.getValue());
            }
            Class jobClass = jobDetail.getJobClass();
            removeJob(jobName);
            addJob(jobName, jobClass, time, data);
            log.info("删除后添加任务：" + jobName + "\n执行时间：" + time);
        }
    }

    /**
     * 移除一个任务(使用默认的任务组名，触发器名，触发器组名)
     *
     * @param jobName
     * @throws SchedulerException
     */
    public void removeJob(String jobName)
            throws SchedulerException {
        //Scheduler scheduler = sf.getScheduler();
        if (!checkJobKeyExists(jobName)) return;
        JobKey jobKey = JobKey.jobKey(jobName, DEFAULT_JOB_GROUP_NAME);
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, DEFAULT_TRIGGER_GROUP_NAME);
        scheduler.pauseTrigger(triggerKey);//停止触发器
        scheduler.unscheduleJob(triggerKey);//移除触发器
        scheduler.deleteJob(jobKey);
    }

    /**
     * 暂停
     *
     * @param jobName
     * @throws SchedulerException
     */
    public void pauseJob(String jobName) throws SchedulerException {
        //Scheduler scheduler = sf.getScheduler();
        if (!checkJobKeyExists(jobName)) return;
        JobKey jobKey = JobKey.jobKey(jobName, DEFAULT_JOB_GROUP_NAME);
        scheduler.pauseJob(jobKey);
    }

    /**
     * 恢复任务
     *
     * @param jobName
     * @throws SchedulerException
     */
    public void resumeJob(String jobName) throws SchedulerException {
        //Scheduler scheduler = sf.getScheduler();
        if (!checkJobKeyExists(jobName)) return;
        JobKey jobKey = JobKey.jobKey(jobName, DEFAULT_JOB_GROUP_NAME);
        scheduler.resumeJob(jobKey);
    }

    /**
     * 暂停所有
     *
     * @throws SchedulerException
     */
    public void pauseALL() throws SchedulerException {
        //Scheduler scheduler = sf.getScheduler();
        scheduler.pauseAll();
    }

    /**
     * 恢复所有
     *
     * @throws SchedulerException
     */
    public void resumeAll() throws SchedulerException {
        //Scheduler scheduler = sf.getScheduler();
        scheduler.resumeAll();
    }

    /**
     * 判断是否存在指定的jobkey
     *
     * @param jobKey
     * @return
     * @throws SchedulerException
     */
    public boolean checkJobKeyExists(String jobKey) throws SchedulerException {
        //Scheduler scheduler = sf.getScheduler();
        return scheduler.checkExists(JobKey.jobKey(jobKey, DEFAULT_JOB_GROUP_NAME));
    }

    /**
     * 触发一个job执行
     *
     * @param jobName
     * @throws SchedulerException
     */
    public void triggerJob(String jobName) throws SchedulerException {
        if (!checkJobKeyExists(jobName)) return;
        scheduler.triggerJob(JobKey.jobKey(jobName, DEFAULT_JOB_GROUP_NAME));
    }

    /**
     * 获得所有执行中的job
     *
     * @return
     * @throws SchedulerException
     */
    public List<JobExecutionContext> getAllJobs() throws SchedulerException {
        return scheduler.getCurrentlyExecutingJobs();
    }

}

